package org.huamoxi.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.jsonwebtoken.Claims;
import org.apache.poi.ss.formula.functions.T;
import org.huamoxi.constant.RedisConstants;
import org.huamoxi.entity.LoginUser;
import org.huamoxi.entity.User;
import org.huamoxi.mapper.LoginMapper;
import org.huamoxi.mapper.UserMapper;
import org.huamoxi.param.LoginParam;
import org.huamoxi.result.Result;
import org.huamoxi.service.LoginService;
import org.huamoxi.utils.CacheUtils;
import org.huamoxi.utils.JwtUtils;
import org.huamoxi.utils.ResultUtils;
import org.huamoxi.utils.ServletUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, User> implements LoginService {

    @Resource
    AuthenticationManager authenticationManager;

    long CACHE_SET_ALIVE_TIME = 7200L;

    @Resource
    UserMapper userMapper;

    @Resource
    CacheUtils cacheUtils;

    @Override
    public Result<T> login(LoginParam param, HttpServletRequest request, HttpServletResponse response) {
        // 验证参数是否正确
        String username = param.getUsername();
        String password = param.getPassword();
        if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
            return ResultUtils.fail("参数错误,请填写账号密码");
        }

        Authentication authenticate;
        // 认证
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            authenticate = authenticationManager.authenticate(authenticationToken);

            if (ObjectUtil.isNull(authenticate)) {
                return ResultUtils.fail("账号或密码错误");
            }

            // 告诉 springseurity 认证成功
            SecurityContextHolder.getContext().setAuthentication(authenticate);
        } catch (AuthenticationException e) {
            return ResultUtils.fail("账号或密码错误");
        }

        // 获取登录的用户
        LoginUser loginUser = (LoginUser)authenticate.getPrincipal();
        // 是否勾选记住我

        // 获取登录的用户信息
        Long userId = loginUser.getId();
        User user = userMapper.selectById(userId);

        // 获取token
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", user.getName());
        claims.put("nickname", user.getNickName());
        claims.put("account", user.getAccount());
        claims.put("id", userId);
        String jwtToken = JwtUtils.generateToken(userId.toString(), claims);

        // 写入缓存. 设置token 2小时过期
        cacheUtils.set(RedisConstants.TOKEN_CACHE_KEY_PREFIX + user.getId(), jwtToken, CACHE_SET_ALIVE_TIME);
        cacheUtils.set(RedisConstants.LOGIN_USER_CACHE_KEY + user.getId(), JSON.toJSONString(claims), CACHE_SET_ALIVE_TIME);
        cacheUtils.set(RedisConstants.USER_CACHE_AUTHORITIES + user.getId(), JSON.toJSONString(loginUser.getAuthorities()), CACHE_SET_ALIVE_TIME);

        // 设置登录时间
//        user.setLastLoginTime(new Date());
//        user.setLastLoginSystem(ServletUtils.doDiscernRequest(request));
//        user.setLastLoginAddress(ServletUtils.getClientIP(request));

        //更新用户登录信息
        userMapper.updateById(user);

        // 其他操作，比如限制单用户登陆，则踢掉原来的用户

        // 返回token
//        return jwtToken;

        return ResultUtils.success(jwtToken);
    }

    @Override
    public String refreshToken(String token) {
        Claims claims = JwtUtils.verifyToken(token);
        if (ObjectUtil.isEmpty(claims)) {
            return "token失效或者不合法";
        }
        return "";
    }
}
